﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects.DataClasses;

namespace ThisIsELearning.Model
{

    public class Address
    {
        public string streetAddress { set; get; }
        public string additionalAddress { set; get; }
        public int postcode { set; get; }
        public string city { set; get; }
        public string state { set; get; }
        public string country { set; get; }

        public Address() { }

        public Address(string add)
        {
            var addr = DataManagerHelper.parseAddressString(add);
            if (addr == null)
                return;

            streetAddress = addr.streetAddress;
            additionalAddress = addr.additionalAddress;
            postcode = addr.postcode;
            city = addr.city;
            state = addr.state;
            country = addr.country;
        }

        public string ToString()
        {
            return streetAddress + ";" + additionalAddress + ";" + postcode + ";" + city + ";" + state + ";" + country;
        }
    }

    public static class DataManagerHelper
    {
        private static DataManager ctx = new DataManager();

        /// <summary>
        /// This method parses a well formatted address string (usually from data store)
        /// into an Address object for easy processing in latter processes. The format
        /// of the address string is as follows:
        /// "[street address];[additional address];[postcode];[city];[state];[country]"
        /// "[street address];;[postcode];[city];[state];[country]" if additional address
        /// is null.
        /// </summary>
        /// <param name="add">Well formatted address string</param>
        /// <returns>An instance of Address with parsed Address of add</returns>
        public static Address parseAddressString(string add)
        {
            string[] tokens = add.Split(new char[]{';'});

            // malformed address string format
            if (tokens.Length != 6)
                return null;

            return new Address()
            {
                streetAddress = tokens[0],
                additionalAddress = string.IsNullOrWhiteSpace(tokens[1]) ? null : tokens[1],
                postcode = Convert.ToInt32(tokens[2]),
                city = tokens[3],
                state = tokens[4],
                country = tokens[5]
            };
        }

        /// <summary>
        /// This method actually duplicates a published learning trail so that it
        /// can be customized for a specific student during the course of his/her
        /// study. What it does is just duplicate the exact contents and then it
        /// is up to the invoker to insert or remove the trai items.
        /// </summary>
        /// <param name="original">Original LearningTrail from DataManager</param>
        /// <returns>The customized learning trail - commited to the database</returns>
        public static LearningTrail createCustomizedTrail(LearningTrail original)
        {
            LearningTrail customized = new LearningTrail
            {
                course = original.course,
                dateCreated = DateTime.Now,
                isSessionCustomized = true,
                learningTrailName = original.learningTrailName,
            };

            foreach (var item in original.trailItems)
            {
                var child = new TrailItem
                {
                    courseTopic = item.courseTopic,
                    learningTrail = customized,
                    trailItemNumber = item.trailItemNumber
                };

                ctx.AddToTrailItems(child);
            }

            ctx.AddToLearningTrails(customized);
            ctx.SaveChanges();

            return customized;
        }

        /// <summary>
        /// This method retrieves user entities from the database
        /// that are of Student type and return them in a List of
        /// Student instances.
        /// </summary>
        /// <returns>List of Student Instances or null if no students</returns>
        public static List<Student> listAllStudents()
        {
            List<Student> toReturn = new List<Student>();
            List<User> lists = ctx.Users.ToList();

            foreach (var iter in lists)
            {
                if (iter is Student)
                    toReturn.Add(iter as Student);
            }

            return toReturn;
        }

        /// <summary>
        /// This method retrieves user entities from the database
        /// that are of Publisher type and return them in a List of
        /// Publisher instances.
        /// </summary>
        /// <returns>List of Publisher Instances or null if no publishers</returns>
        public static List<Publisher> listAllPublishers()
        {
            List<Publisher> toReturn = new List<Publisher>();
            List<User> lists = ctx.Users.ToList();

            foreach (var iter in lists)
            {
                if (iter is Publisher)
                    toReturn.Add(iter as Publisher);
            }

            return toReturn;
        }

        /// <summary>
        /// This method retrieves user entities from the database
        /// that are of Parents type and return them in a List of
        /// Parents instances.
        /// </summary>
        /// <returns>List of Parents Instances</returns>
        public static List<Parent> listAllParents()
        {
            List<Parent> toReturn = new List<Parent>();
            List<User> lists = ctx.Users.ToList();

            foreach (var iter in lists)
            {
                if (iter is Parent)
                    toReturn.Add(iter as Parent);
            }

            return toReturn;
        }

        /// <summary>
        /// This method retrieves user entities from the database
        /// that are of Admin type and return them in a List of
        /// Admin instances.
        /// </summary>
        /// <returns>List of Parents Instances</returns>
        public static List<Admin> listAllAdmins()
        {
            List<Admin> toReturn = new List<Admin>();
            List<User> lists = ctx.Users.ToList();

            foreach (var iter in lists)
            {
                if (iter is Admin)
                    toReturn.Add(iter as Admin);
            }

            return toReturn;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<ItemObjectType> listAllItemObjectTypes()
        {
            return ctx.ItemObjectTypes.ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<LearningStyle> listAllLearningStyles()
        {
            return ctx.LearningStyles.ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="publishingCompanyId"></param>
        /// <returns></returns>
        public static PublishingCompany getPublishingCompany(int publishingCompanyId)
        {
            var company = (from c in ctx.PublishingCompanies
                           where c.publishingCompanyId == publishingCompanyId
                           select c);
            if (!company.Any())
                return null;

            return company.First();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static string generateRandomFileName(string ext)
        {
            string fileName = "";
            Random random = new Random((int)DateTime.Now.Ticks);

            for (int i = 0; i < 15; ++i)
            {
                fileName += "" + (random.Next(1, 54321) % random.Next(1,10));
            }

            return fileName + "." + ext;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="contentType"></param>
        /// <returns></returns>
        public static int ensureCanvasNumber(int parentId, string contentType)
        {
            List<ContentCanvas> canvases = null;
            switch (contentType)
            {
                case "C":
                case "c":
                    var c = ctx.TopicContents.Where(a => a.topicContentId == parentId);
                    if (c.Any())
                        canvases = c.First().contentCanvas.ToList();
                    break;
                case "Q":
                case "q":
                    var q = ctx.TopicQuestions.Where(a => a.topicQuestionId == parentId);
                    if (q.Any())
                        canvases = q.First().contentCanvas.ToList();
                    break;
                default:
                    return -1;
            }

            if (canvases == null)
                return -1;

            var s = canvases.OrderBy(a => a.canvasNumber);
            List<ContentCanvas> sorted = s.ToList();
            for (int i = 0; i < sorted.Count; ++i)
                    sorted[i].canvasNumber = i + 1;

            return sorted.Count + 1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="courseId"></param>
        /// <returns></returns>
        public static int ensureCourseTopicNumber(int courseId)
        {
            var s = ctx.CourseTopics.Where(a => a.course.courseId == courseId);
            if (!s.Any())
                return 1;

            var q = s.OrderBy(a => a.courseTopicNumber);
            List<CourseTopic> topics = q.ToList();
            for (int i = 0; i < topics.Count; ++i)
                topics[i].courseTopicNumber = i + 1;

            return topics.Count + 1;
        }

        public static int ensureTrailItemNumber(int learningTrailId)
        {
            var s = ctx.TrailItems.Where(a => a.learningTrail.learningTrailId == learningTrailId);
            if (!s.Any())
                return 1;

            var q = s.OrderBy(a => a.trailItemNumber);
            List<TrailItem> items = q.ToList();
            for (int i = 0; i < items.Count; ++i)
                items[i].trailItemNumber = i + 1;

            return items.Count + 1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        /// <param name="manager"></param>
        /// <returns></returns>
        public static T[] detachAllReferences<T>(T[] entities, DataManager manager)
        {
            if (entities == null || entities.Length < 1 || !(entities[0] is EntityObject))
                return null;

            foreach (var entity in entities)
                manager.Detach(entity);

            return entities;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static T[] detachAllReferences<T>(T[] entities)
        {
            if (entities == null || entities.Length < 1 || !(entities[0] is EntityObject))
                return null;

            foreach (var entity in entities)
                ctx.Detach(entity);

            return entities;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static DataManager getDataManager()
        {
            return ctx;
        }

    }
}